﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using Cwing.UI.Validation;
using System.ComponentModel;
using System.Web.UI;

using V = Cwing.UI.Validation;
using Cwing.UI.Validation.Manager;

namespace Cwing.UI.Controls
{
    public class ValidationTextBox : TextBox, IValidation
    {
        public ValidationTextBox()
        {
            ValidationResult = V.ValidationResult.Empty;
        }

        private static readonly Object ControlValidatingCommand = new object();

        private static readonly Object ControlValidateCommand = new object();

        #region IValidation Members

        protected Int32 _index = 0;

        private Configuration _configuration;

        /// <summary>
        /// If User cancel the validation, OnValidate will not trigger
        /// </summary>
        /// <returns></returns>
        public ValidationResult Validate()
        {
            if (Enabled == false || Visible == false || CheckParentEnabled(this.Parent) == false)
            {
                return V.ValidationResult.Empty;
            }

            if (ValidationType == ValidationType.Client)
            {
                return V.ValidationResult.Empty;
            }
            else
            {
                if (IsValidate == false)
                {
                    IsValidate = true;

                    ValidationResult _result = V.ValidationResult.Empty;

                    //Before Validate
                    ValidatingEventArgs e = new ValidatingEventArgs();
                    e.Cancel = false;
                    e.Control = this;
                    V.ValidationResult preValidationResult = OnControlValidating(e);
                    if (e.Cancel)
                    {
                        return V.ValidationResult.Empty;
                    }

                    if (!preValidationResult.IsEmpty && !preValidationResult.Result)
                    {
                        ValidationResult = preValidationResult;

                        return preValidationResult;
                    }

                    _result = new ControlValidationManager(Text, this).Validate();

                    //After Validate
                    ValidateEventArgs afterE = new ValidateEventArgs();
                    afterE.Control = this;
                    ValidationResult = OnControlValidate(afterE, _result);
                }

                return ValidationResult;

            }

        }

        [Browsable(false), DefaultValue((String)null), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ValidationResult ValidationResult
        {
            get;
            set;
        }

        [Category("Validation"), Description("XPath of Configure element")]
        public String Path
        {
            get;
            set;
        }

        [Category("Validation"), Description("Error message container")]
        [IDReferenceProperty, TypeConverter(typeof(ErrorListConverter))]
        public String ValidationSummary
        {
            get;
            set;
        }

        [Category("Validation"), Description("Validate Index of Control")]
        public int Index
        {
            get { return _index; }
            set
            {
                _index = value;
            }
        }

        [Browsable(false)]
        public ErrorList ErrorMessageContainer
        {
            get
            {
                if (!String.IsNullOrEmpty(ValidationSummary))
                {
                    return FindControl(ValidationSummary) as ErrorList;
                }
                else
                {
                    return null;
                }
            }
        }

        [Browsable(false)]
        public Configuration ValidationConfiguration
        {
            get
            {
                if (_configuration == null && !String.IsNullOrEmpty(Path))
                {
                    _configuration = ValidationConfigHelper.FetchConfigNode(Path);
                }

                return _configuration;
            }
        }

        public Boolean isRendError = false;

        /// <summary>
        /// Identify the error message is rended
        /// </summary>
        [Browsable(false)]
        public Boolean IsRendError
        {
            get
            {
                return isRendError;
            }
            set
            {
                isRendError = value;
            }
        }

        private Boolean isValidate = false;

        /// <summary>
        /// Identify the Validate method wether be called.
        /// </summary>
        [Browsable(false)]
        public Boolean IsValidate
        {
            get
            {
                return isValidate;
            }
            set
            {
                isValidate = value;
            }
        }

        [Browsable(true), Category("Validation"), Description("Validation Group")]
        public string GroupName
        {
            get;
            set;
        }

        /// <summary>
        /// raise after Validate Method been callled
        /// </summary>
        [Category("Validation"), Description("Raise after validated, user can change validate result")]
        public event ControlValidated Validated
        {
            add
            {
                base.Events.AddHandler(ControlValidateCommand, value);
            }
            remove
            {
                base.Events.RemoveHandler(ControlValidateCommand, value);
            }
        }

        /// <summary>
        /// raise before Validate Method be called
        /// </summary>
        [Category("Validation"), Description("Raise before validate, Validate Result is readonly")]
        public event ControlValidating Validating
        {
            add
            {
                base.Events.AddHandler(ControlValidatingCommand, value);
            }
            remove
            {
                base.Events.RemoveHandler(ControlValidatingCommand, value);
            }
        }

        #endregion

        /// <summary>
        /// Be override, auto render the max length in Configuration is have
        /// </summary>
        [Browsable(false)]
        public override int MaxLength
        {
            get
            {
                if (DesignMode)
                {
                    return base.MaxLength;
                }
                else
                {
                    if (TextMode != TextBoxMode.MultiLine && ValidationConfiguration != null)
                    {
                        return ValidationConfiguration.MaxLength;
                    }
                    else
                    {
                        return base.MaxLength;
                    }
                }
            }
            set
            {
                base.MaxLength = value;
            }
        }

        private ValidationResult OnControlValidating(ValidatingEventArgs e)
        {
            ControlValidating hanlder = base.Events[ControlValidatingCommand] as ControlValidating;
            V.ValidationResult preResult = V.ValidationResult.Empty;
            if (hanlder != null)
            {
                hanlder(e, preResult);
            }
            return preResult;
        }

        private ValidationResult OnControlValidate(ValidateEventArgs e, ValidationResult result)
        {
            ControlValidated hanlder = base.Events[ControlValidateCommand] as ControlValidated;
            if (hanlder != null)
            {
                hanlder(e, result);
            }
            return result;
        }

        private ValidationType type = ValidationType.Server;

        [Category("Validation")]
        public ValidationType ValidationType
        {
            get
            {
                return type;
            }
            set
            {
                type = value;
            }
        }

        [Browsable(false)]
        public WebControl Self
        {
            get
            {
                return this;
            }
        }

        public String ToClientScript()
        {
            if (Enabled == false || Visible == false || CheckParentEnabled(this.Parent) == false || _isRendClientScript == true)
            {
                return String.Empty;
            }

            _isRendClientScript = true;

            return String.Format("[{0},\"{1}\",\"{2}\",\"{3}\",\"{4}\",{5},\"{6}\",{7},{8},\"{9}\",\"{10}\",\"{11}\"]",
                Index, GroupName, "N", Self.ClientID,
                (ErrorMessageContainer != null ? ErrorMessageContainer.ClientID : ""),
                ValidationConfiguration.Mandatory.ToString().ToLower(),
                ValidationConfiguration.MandatoryMessage, ValidationConfiguration.MinLength, ValidationConfiguration.MaxLength,
                ValidationConfiguration.LengthMessage, ValidationConfiguration.TypeRegEx.Replace(@"\", @"\\"), ValidationConfiguration.TypeMessage);
        }

        private Boolean _isRendClientScript = false;

        internal Boolean CheckParentEnabled(Control ctrl)
        {
            if (ctrl is WebControl && ctrl.Visible == true)
            {
                if (((WebControl)ctrl).Enabled == false || ctrl.Visible == false)
                {
                    return false;
                }
                else
                {
                    return CheckParentEnabled(ctrl.Parent);
                }
            }
            else
            {
                return true;
            }
        }
    }
}
